package mining;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ModifyDataset {
	final BufferedWriter modified;
	final BufferedWriter basenum;
	final BufferedWriter mapping;
	final BufferedReader br;
	String modifiedDelimiter = ",";
	String basenumDelimiter = " ";

	public static void main(String[] args) throws IOException {
		ModifyDataset md;
//		md = new ModifyDataset("./datasets/chess/kr-vs-kp.data");
//		md.doNonBooleanMapping();
//		md = new ModifyDataset("./datasets/connect4/connect-4.data");
//		md.doNonBooleanMapping(Arrays.asList("b"));
//		md = new ModifyDataset("./datasets/mushroom/agaricus-lepiota.data");
//		md.doNonBooleanMapping();
//		md = new ModifyDataset("./datasets/primary_tumor/primary-tumor.data");
//		md.doNonBooleanMapping();
//		md = new ModifyDataset("./datasets/soybean_large/soybean-large.data");
//		md.doNonBooleanMapping();
//		md = new ModifyDataset("./datasets/spect/SPECT.all");
//		md.doNonBooleanMapping();
//		md = new ModifyDataset("./datasets/voting_records/house-votes-84.data");
//		md.doNonBooleanMapping();
//		md = new ModifyDataset("./datasets/zoo/zoo.data");
//		md.doNonBooleanMapping();
//		md = new ModifyDataset("./datasets/dermatology/dermatology.data");
//		md.doNonBooleanMapping();
//		md = new ModifyDataset("./datasets/adult/adult.all");
//		md.doNonBooleanMapping();
//		md = new ModifyDataset("./datasets/flags/flags.data");
//		md.doNonBooleanMapping();
		md = new ModifyDataset("./datasets/tae/tae.data");
		md.doNonBooleanMapping();
//		md = new ModifyDataset("./datasets/monk/monks.all");
//		md.doNonBooleanMapping();
////		md = new ModifyDataset("./datasets/census/USCensus1990.data.txt");
////		md.modifyUSCensusData();
//		md = new ModifyDataset("./datasets/census/USCensus1990.data");
//		md.doNonBooleanMapping();
//		String loc = "./datasets/mock/mock.data";
//		for (int i = 0; i < 8; i++) {
//			md = new ModifyDataset(loc + "." + i);
//			md.doItemMapping();
//		}
//		File dir = new File("./datasets/syn");
//		for(File f : dir.listFiles(new FilenameFilter() {
//			@Override
//			public boolean accept(File dir, String name) {
//				return name.endsWith(".data");
//			}
//		})){
//			md = new ModifyDataset(f.getPath());
//			md.doItemMapping();
//		}
	}
	
	private void modifyUSCensusData() throws IOException{
		CsvReader cr = new CsvReader(this.filePath);
		List<String> list;
		BufferedWriter bw = new BufferedWriter(new FileWriter("./datasets/census/USCensus1990.data"));
		while ((list = cr.stringRead()) != null) {
			boolean firstSpace = true;
			for (int i = 1; i < list.size(); i++) {
				if (!firstSpace) {
					bw.append(",");
				} else {
					firstSpace = false;
				}
				bw.write(list.get(i));
			}
			bw.newLine();
		}
		bw.flush();
	}
	
	private void append(int i) throws IOException {
		modified.append(Integer.toString(i));
		basenum.append(Integer.toString(i + 1));
	}
	private void appendDelimiter() throws IOException {
		modified.append(modifiedDelimiter);
		basenum.append(basenumDelimiter);
	}
	private void appendLineDelimiter() throws IOException {
		modified.newLine();
		basenum.newLine();
	}
	private void flush() throws IOException {
		modified.flush();
		basenum.flush();
	}

	String filePath;
	public ModifyDataset(String inputFilePath) throws IOException {
		System.out.println("processing: " + inputFilePath);
		this.filePath = inputFilePath;
		br = new BufferedReader(new FileReader(inputFilePath));
		modified = new BufferedWriter(new FileWriter(inputFilePath + ".modified"));
		basenum = new BufferedWriter(new FileWriter(inputFilePath + ".basenum"));
		mapping = new BufferedWriter(new FileWriter(inputFilePath + ".translation"));
	}
	
//	int lastDocId = 0;
//	public void run2() throws IOException {
//		CsvReader cr = CsvReader.getNewReader();
//		CsvReader.setDelimiter(",");
//		List<String> list;
//		while ((list = cr.stringRead()) != null) {
//			if (list.size() != 3)
//				continue;
//			int newDocId = Integer.parseInt(list.get(0));
//			if (lastDocId != newDocId) {
//				if (lastDocId != 0)
//					appendLineDelimiter();
//				lastDocId = newDocId; 
//			} else {
//				appendDelimiter();
//			}
//			append(list.get(1));
//		}
//		this.modified.flush();
//	}
	
	public void modifyFile() {
		try {
			while(br.ready()) {
				String[] list = br.readLine().split(this.modifiedDelimiter);
				if (list.length <= 1) {
					continue;
				}
				int i = 0;
				for (String item : list) {
					if (i != 0) {
						appendDelimiter();
					}
					modified.write(i++ + item);
				}
				appendLineDelimiter();
			}
			modified.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public void doItemMapping() throws IOException {
		Map<String, Integer> convert = new HashMap<String, Integer>();
//		Map<Integer, String> convertBack = new HashMap<Integer, String>();
		CsvReader cr = new CsvReader(this.filePath);
		List<String> list;
		int nextConvertedValue = 0;
		while ((list = cr.stringRead()) != null) {
			boolean firstSpace = true;
			for (String item : list) {
				if (!item.trim().isEmpty()) {
					int convertedValue;
					if (!firstSpace) {
						appendDelimiter();
					} else 
						firstSpace = false;
					if (convert.containsKey(item)) {
						append(convert.get(item));
					} else {
						convertedValue = nextConvertedValue++;
						convert.put(item, convertedValue);
						append(convertedValue);
//						convertBack.put(convertedValue, item);
						mapping.append(convertedValue + modifiedDelimiter + item);
						mapping.newLine();
					}
				}
			}
			appendLineDelimiter();
		}
		flush();
		mapping.flush();
	}
	
	public void doNonBooleanMapping() throws IOException {doNonBooleanMapping(Collections.<String>emptyList());}
	public void doNonBooleanMapping(List<String> ignoreList) throws IOException {
		//Map<Position, Map<Name, ConvertedValue>>
		Map<Integer, Map<String, Integer>> mapToConverted = new HashMap<Integer, Map<String, Integer>>();
		//Map<ConvertedValue, PositionValuePair>
//		Map<Integer, PositionValuePair> mapToPositionItem = new HashMap<Integer, PositionValuePair>();
		
		CsvReader cr = new CsvReader(this.filePath);
		List<String> list;
		int nextConvertedValue = 0;
		while ((list = cr.stringRead()) != null) {
			int i = 0;
			boolean firstSpace = true, emptyLine = true;
			for (String item : list) {
				if (!item.trim().isEmpty() && !ignoreList.contains(item)) {
					int convertedValue;
					emptyLine = false;
					if (!firstSpace) {
						appendDelimiter();
					} else
						firstSpace = false;
					if (!mapToConverted.containsKey(i)) {
						mapToConverted.put(i, new HashMap<String, Integer>(3));
					}
					
					Map<String, Integer> positionMap = mapToConverted.get(i);
					if (positionMap.containsKey(item)) {
						convertedValue = positionMap.get(item); 
					} else {
						convertedValue = nextConvertedValue++;
						positionMap.put(item, convertedValue);
//						mapToPositionItem.put(convertedValue, new PositionValuePair(i, item));
						mapping.append(convertedValue + modifiedDelimiter + i + modifiedDelimiter + item);
						mapping.newLine();
					}
					append(convertedValue);
				}
				i++;
			}
			if (!emptyLine)
				appendLineDelimiter();
		}
		flush();
		mapping.flush();
	}
	
//	private class PositionValuePair {
//		private final int position;
//		private final String value;
//		PositionValuePair(int position, String value) {
//			this.position = position;
//			this.value = value;
//		}
//		
//		@Override
//		public String toString() {
//			return this.position + this.value;
//		}
//		
//		@Override
//		public boolean equals(Object o) {
//			if (o.getClass() != this.getClass())
//				return false;
//			PositionValuePair p = (PositionValuePair) o;
//			if (this.position == p.position && this.value == p.value) {
//				return true;
//			}
//			return false;
//		}
//	}
}
